﻿using System;
using System.Collections.Generic;
using System.Text;

namespace DimensionsHelper.Common.Utils;

/// <summary>
///     用于表示文本内容的定义替换。
///     <list type="number">
///         <item>
///             <term>${}</term> 占位标识符，允许使用回调进行替换。
///         </item>
///         <item>
///             <term>$r{}</term> 保留值占位符。
///             在占位标识符匹配失败时，将保留其中的内容，并忽略其他内容。
///             匹配成功时，进行一般替换。
///         </item>
///         <item>
///             <term>$a{}</term> 别名占位符，不参与最终文本
///         </item>
///         <item>
///             其他文本视为一般字符串。
///         </item>
///     </list>
/// </summary>
public class Replacer
{
    private PlaceHolder? _alias;
    private PlaceHolder? _remaining;

    internal Replacer()
    {
        _remaining = null;
        PlaceHolders = [];
        HasIdentifier = false;
    }

    internal List<PlaceHolder> PlaceHolders
    {
        get;
    }


    /// <summary>
    ///     表达式中的保留值。
    /// </summary>
    public string? Remaining => _remaining?.TextBuilder.ToString();


    /// <summary>
    ///     表达式中定义的别名
    /// </summary>
    public string? Alias => _alias?.TextBuilder.ToString();


    /// <summary>
    ///     表达式中是否包含占位标识符
    /// </summary>
    public bool HasIdentifier
    {
        get; private set;
    }


    /// <summary>
    ///     表达式是否是纯文本
    /// </summary>
    public bool IsPureText => PlaceHolders.Count == 1 && 
                              PlaceHolders[PlaceHolders.Count - 1].Kind == PlaceHolderKind.Text;


    internal void Append(PlaceHolder placeHolder)
    {
        if (placeHolder.Kind == PlaceHolderKind.Remaining)
        {
            if (_remaining != null)
            {
                throw new Exception("'$r{}'保留内容在一个表达式中只能出现一次。");
            }

            _remaining = placeHolder;
        }
        else if (placeHolder.Kind == PlaceHolderKind.Alias)
        {
            if (_alias != null)
            {
                throw new Exception("'$a{}'保留内容在一个表达式中只能出现一次。");
            }

            _alias = placeHolder;
            // 别名不影响最终值，不加入占位符列表中
            return;
        }
        else if (placeHolder.Kind == PlaceHolderKind.Identifier)
        {
            HasIdentifier = true;
        }

        PlaceHolders.Add(placeHolder);
    }


    /// <summary>
    ///     根据已有占位定义进行内容替换。
    /// </summary>
    /// <param name="getter">获取占位标识符内容的回调，如果此参数是null，将忽略所有占位标识符。</param>
    public string Replace(Func<string, string?>? getter)
    {
        var str = new StringBuilder();

        foreach (var item in PlaceHolders)
        {
            switch (item.Kind)
            {
                case PlaceHolderKind.Text:
                case PlaceHolderKind.Remaining:
                    str.Append(item.TextBuilder);
                    break;

                case PlaceHolderKind.Identifier:
                    string? placeHolderValue = null;
                    if (getter != null)
                    {
                        placeHolderValue = getter(item.TextBuilder.ToString());
                    }

                    if (placeHolderValue == null)
                    {
                        if (_remaining != null)
                        {
                            return _remaining.TextBuilder.ToString();
                        }
                    }
                    else
                    {
                        str.Append(placeHolderValue);
                    }

                    break;
            }
        }

        return str.ToString();
    }
}